#ifndef TINX_TASK_H
#define TINX_TASK_H

#include <tinx/interrupt.h>
#include <tinx/signal.h>
#include <tinx/bitmap.h>
#include <tinx/list.h>

#define TASK_NR 128
#define OPEN_NR 32

enum
{
    TASK_FLAG_FPU_SSE_USED = 0x1
};

typedef struct user_desc_t
{
    u32 entry_number;
    u32 base_addr;
    u32 limit;
    u32 seg_32bit : 1;
    u32 contents : 2;
    u32 read_exec_only : 1;
    u32 limit_in_pages : 1;
    u32 seg_not_present : 1;
    u32 useable : 1;
} _packed user_desc_t;

typedef struct tls_t
{
    u32 addr;
    u32 size;
    bool special; // 用户空间自己提供 tls 空间
    user_desc_t *desc;
} tls_t;

typedef enum task_state_t
{
    TASK_INIT,
    TASK_READY,
    TASK_RUNNING,
    TASK_BLOCKED,
    TASK_SLEEPPING,
    TASK_WAITING,
    TASK_DIED
} task_state_t;

typedef struct task_frame_t
{
    u32 esi;
    u32 edi;
    u32 ebx;
    u32 ebp;
    void *eip;
} _packed task_frame_t;

typedef struct task_t
{
    u32 stack;
    char name[16];
    task_state_t state;
    pid_t pid;
    pid_t ppid;
    pid_t *exittid;
    uid_t uid;
    pid_t waitpid;
    int status;
    list_node_t rnode;
    list_node_t unode;
    list_node_t node;
    u32 jiffies;
    u16 prio;
    u16 ticks;
    u32 flags;
    u32 pgdir;
    bitmap_t *vmap;
    u32 brk;
    u32 exec;
    u32 end;
    u32 text;
    u32 data;
    u16 umask;
    tls_t *tls;
    void *fpusse;
    int blocked;
    int signal;
    struct sigaction_t actions[MAXSIG + 1];
    struct inode_t *iroot;
    struct inode_t *ipwd;
    struct inode_t *iexec;
    struct file_t *files[OPEN_NR];
} task_t;

task_t *running_task();
void schedule();

void task_activity(task_t *task);

task_t *task_create(char *name, u8 prio, handler_t handler, uid_t uid);
void task_to_user_mode(handler_t target);

void task_yield();
pid_t task_fork();
void task_exit(int status);
pid_t task_waitpid(pid_t pid, int *status, int options);
int sys_execve(char *filename, char *argv[], char *envp[]);

int task_block(task_t *task, int state);
void task_unblock(task_t *task, int status);

fd_t task_get_file(task_t *task);
void task_put_file(task_t *task, fd_t fd);

pid_t task_getpid();
pid_t task_getppid();
pid_t task_getuid();

#endif